// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
/* Copyright (c) 2021 Sartura
 * Based on minimal.c by Facebook */

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <sys/resource.h>
#include <bpf/libbpf.h>
#include "nwatch.skel.h"


#include "nwatch.h"
#include <getopt.h>

static const char *__doc__ = 
"usage: %s [OPTS] \n"
"   three trace mode to achieve different functions.\n"
"\nOPTS:\n"
"    -h    look the help info \n"
"    -f    the basic 5 hooks and so on \n"
"    -t    monitor about long tcp connection  \n"
"    -d    monitor about drop package \n";

static const struct option long_options[] = {
	{ "help", no_argument, NULL, 'h' },
	{ "filter", no_argument, NULL, 'f' },
	{ "tcp", required_argument, NULL, 't' },
	{ "drop", no_argument, NULL, 'p' },
	{}
};

g_paras_t g_paras = {"global parameters", 0, 0};

void nwatch_usage(char *argv[], const struct option *long_options,
		  		const char *doc, bool error)
{
	int i;

	printf("\n%s\nOption for %s:\n", doc, argv[0]);
	for (i = 0; long_options[i].name != 0; i++) {
		printf(" --%-15s", long_options[i].name);
		if (long_options[i].flag != NULL)
			printf(" flag (internal value: %d)",
			       *long_options[i].flag);
		else
			printf("\t short-option: -%c", long_options[i].val);
		printf("\n");
	}
	printf("\n");
}

int cmd_opts_analytic(int argc, char **argv)
{
	int ret = 0;
	bool error = true;
	int opt;
	int longindex = 0;
	
	/* Parse commands line args */
	while ((opt = getopt_long(argc, argv, "hft:d",
				  long_options, &longindex)) != -1) {
		switch (opt) {
		case 'h':
			error = false;
                        goto err_out;
		case 'f':
			g_paras.trace_mode = 1;
			break;
		case 't':
			g_paras.trace_mode = 2;
			g_paras.tcp_time = atoi(optarg);
			break;
		case 'd':
			g_paras.trace_mode = 3;
			break;
		default:
			error = true;
			goto err_out;
		}
	}

	return ret;

err_out:
	nwatch_usage(argv, long_options, __doc__, error);
	return -1;
}

static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)
{
        return vfprintf(stderr, format, args);
}

static volatile sig_atomic_t stop;

static void sig_int(int signo)
{
        stop = 1;
}

int main(int argc, char **argv)
{
        int ret = 0;
	ret = cmd_opts_analytic(argc, argv);
	if(ret < 0){

		return -1;
	}

	printf("name is:%s trace_mode is :%d tcp_time is :%d\n", g_paras.name, g_paras.trace_mode, g_paras.tcp_time);
	
	struct nwatch_bpf *skel;
        int err;

        /* Set up libbpf errors and debug info callback */
        libbpf_set_print(libbpf_print_fn);

        /* Open load and verify BPF application */
        skel = nwatch_bpf__open_and_load();
        if (!skel) {
                fprintf(stderr, "Failed to open BPF skeleton\n");
                return 1;
        }

        /* Attach tracepoint handler */
        err = nwatch_bpf__attach(skel);
        if (err) {
                fprintf(stderr, "Failed to attach BPF skeleton\n");
                goto cleanup;
        }

        if (signal(SIGINT, sig_int) == SIG_ERR) {
                fprintf(stderr, "can't set signal handler: %s\n", strerror(errno));
                goto cleanup;
        }

        printf("Successfully started! Please run `sudo cat /sys/kernel/debug/tracing/trace_pipe` "
               "to see output of the BPF programs.\n");

        while (!stop) {
                fprintf(stderr, ".");
                sleep(1);
        }

cleanup:
        nwatch_bpf__destroy(skel);
        return -err;
}

